package com.quectel.emp.controller.scheduling;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.constant.core.scheduling.SchedulingAttendanceDailyConstants;
import com.quectel.constant.core.scheduling.SchedulingAttendanceGroupConstants;
import com.quectel.constant.core.scheduling.SchedulingCalendarConfigConstants;
import com.quectel.core.module.dept.dto.DeptPersonDto;
import com.quectel.core.module.dept.service.DeptPersonService;
import com.quectel.core.module.scheduling.dto.*;
import com.quectel.core.module.scheduling.service.*;
import com.quectel.core.module.schedulingapply.service.SchedulingApplyRecordService;
import com.quectel.core.module.workorder.service.WorkOrderService;
import com.quectel.emp.controller.BaseController;
import com.quectel.emp.util.SessionHolder;
import com.quectel.emp.vo.scheduling.GroupPersonWorkShiftResp;
import com.quectel.emp.vo.scheduling.GroupPersonWorkTimeResp;
import com.quectel.util.common.DateUtils;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 在这里编写说明
 *
 * @author: bob
 * @email: bob.yu@quectel.com
 * @date: 2023-07-26 14:41:00
 */
@RestController
@RequestMapping("schedulingCalendar")
@Tag(name = "SchedulingCalendarController", description = "考勤日历相关api")
public class SchedulingCalendarController extends BaseController {


    @DubboReference
    private WorkOrderService workOrderService;
    @DubboReference
    private SchedulingApplyRecordService schedulingApplyRecordService;
    @DubboReference
    private SchedulingAttendanceGroupPersonWorkTimeConfigService schedulingAttendanceGroupPersonWorkTimeConfigService;
    @DubboReference
    private DeptPersonService deptPersonService;
    @DubboReference
    private SchedulingTimeConfigService schedulingTimeConfigService;
    @DubboReference
    private SchedulingAttendanceGroupService schedulingAttendanceGroupService;
    @DubboReference
    private SchedulingAttendanceGroupPersonBindingService groupPersonBindingService;
    @DubboReference
    private SchedulingCalendarConfigService calendarConfigService;
    @DubboReference
    private SchedulingCalendarConfigBindingService calendarConfigBindingService;

    @GetMapping("checkDateWorkTimeInfo")
    @Operation(summary = "查看选中日期的具体工具时间段以及绑定人员")
    public Response<List<GroupPersonWorkShiftResp>> checkDateWorkTimeInfo(
            @Parameter(description = "考勤组id") @RequestParam(required = true) Long groupId,
            @Parameter(description = "日期 yyyy-MM-dd", required = true) @RequestParam String day) {

        SessionHolder.getEmp();

        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));

        SchedulingAttendanceGroupDto schedulingAttendanceGroupDto = schedulingAttendanceGroupService.selectById(groupId);
        if (schedulingAttendanceGroupDto == null) {
            return Response.error("考勤组不存在，请联系管理员");
        }

        request.put(LambdaUtil.getFieldName(SchedulingAttendanceGroupPersonWorkTimeConfigDto::getSchedulingAttendanceGroupId), groupId);

        List<GroupPersonWorkShiftResp> resultList = new ArrayList();

        // 固定班
        if (schedulingAttendanceGroupDto.getShiftSystemType().equals(SchedulingAttendanceGroupConstants.SchedulingTypeEnum.FIX.getType())) {

            List<DeptPersonDto> deptPersonDtos = new ArrayList<>();
            List<SchedulingAttendanceGroupPersonBindingDto> groupPersonBindingDtos = groupPersonBindingService.selectListByGroupId(groupId);
            for (SchedulingAttendanceGroupPersonBindingDto groupPersonBindingDto : groupPersonBindingDtos) {
                DeptPersonDto deptPersonDto = deptPersonService.selectCacheById(groupPersonBindingDto.getPersonId());
                if (deptPersonDto != null) {
                    deptPersonDtos.add(deptPersonDto);
                }
            }

            // 查询配置
            List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> schedulingAttendanceGroupPersonWorkTimeConfigDtos =
                    schedulingAttendanceGroupPersonWorkTimeConfigService.queryListWithoutPadding(request.getParams());

            if (CollectionUtils.isEmpty(schedulingAttendanceGroupPersonWorkTimeConfigDtos)) {
                return Response.error("当前日期没有排班");
            }

            SchedulingAttendanceGroupPersonWorkTimeConfigDto personWorkTimeConfigDto = schedulingAttendanceGroupPersonWorkTimeConfigDtos.get(0);
            List<FixWorkTimeBindingDto> fixWorkTimeBindingDtos = JacksonUtils.parseArray(personWorkTimeConfigDto.getTimeConfigArr(), FixWorkTimeBindingDto.class);
            List<FixWorkTimeBindingDto> fixWorkTimeBindingConfig = fixWorkTimeBindingDtos.parallelStream()
                    .collect(Collectors.groupingBy(FixWorkTimeBindingDto::getDay))
                    .get(DateUtil.dayOfWeekEnum(DateUtil.parse(day, DateUtils.FormatType.SIMPLE.getType())).getValue()
                    );
            List<SchedulingTimeConfigDto> timeConfigDtoList = fixWorkTimeBindingConfig.get(0).getTimeConfigDtoList();
            for (SchedulingTimeConfigDto schedulingTimeConfigDto : timeConfigDtoList) {
                GroupPersonWorkShiftResp shiftResp = new GroupPersonWorkShiftResp();
                shiftResp.setTimeConfigName(schedulingTimeConfigDto.getName());
                shiftResp.setWorkTime(schedulingTimeConfigDto.getWorkTime());
                shiftResp.setClosingTime(schedulingTimeConfigDto.getClosingTime());
                shiftResp.setPersons(deptPersonDtos);
                resultList.add(shiftResp);
            }
        }

        // 手动排班
        if (schedulingAttendanceGroupDto.getShiftSystemType().equals(SchedulingAttendanceGroupConstants.SchedulingTypeEnum.SCHEDULING.getType())) {
            // 查询配置
            // 具体日期条件
            request.put(LambdaUtil.getFieldName(SchedulingAttendanceGroupPersonWorkTimeConfigDto::getDate), day);

            List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> schedulingAttendanceGroupPersonWorkTimeConfigDtos =
                    schedulingAttendanceGroupPersonWorkTimeConfigService.queryListWithoutPadding(request.getParams());

            if (CollectionUtils.isEmpty(schedulingAttendanceGroupPersonWorkTimeConfigDtos)) {
                return Response.error("当前日期没有排班等");
            }

            Set<SchedulingTimeConfigDto> timeConfigSets = new HashSet<>();
            for (SchedulingAttendanceGroupPersonWorkTimeConfigDto groupPersonWorkTimeConfigDto : schedulingAttendanceGroupPersonWorkTimeConfigDtos) {
                // 这里查询出来都是人和时间配置的关系
                List<SchedulingTimeConfigDto> configDtos = JacksonUtils.parseArray(groupPersonWorkTimeConfigDto.getTimeConfigArr(), SchedulingTimeConfigDto.class);
                for (SchedulingTimeConfigDto timeConfigDto : configDtos) {
                    timeConfigSets.add(timeConfigDto);
                }
            }

            List<GroupPersonWorkShiftResp.TimeConfigPerson> timeConfigPersonArrayList = new ArrayList<>();
            for (SchedulingAttendanceGroupPersonWorkTimeConfigDto groupPersonWorkTimeConfigDto : schedulingAttendanceGroupPersonWorkTimeConfigDtos) {
                // 这里查询出来都是人和时间配置的关系
                Long personId = groupPersonWorkTimeConfigDto.getPersonId();
                List<SchedulingTimeConfigDto> configDtos = JacksonUtils.parseArray(groupPersonWorkTimeConfigDto.getTimeConfigArr(), SchedulingTimeConfigDto.class);
                for (SchedulingTimeConfigDto timeConfigDto : configDtos) {
                    GroupPersonWorkShiftResp.TimeConfigPerson timeConfigPerson = new GroupPersonWorkShiftResp.TimeConfigPerson();
                    timeConfigPerson.setTimeConfigDto(timeConfigDto);
                    timeConfigPerson.setDeptPersonId(personId);
                    timeConfigPersonArrayList.add(timeConfigPerson);
                }
            }

            List<SchedulingTimeConfigDto> uniqueTimeConfigs = new ArrayList<>(timeConfigSets);
            for (SchedulingTimeConfigDto timeConfigDto : uniqueTimeConfigs) {
                GroupPersonWorkShiftResp resp = new GroupPersonWorkShiftResp();
                resp.setTimeConfigName(timeConfigDto.getName());
                resp.setWorkTime(timeConfigDto.getWorkTime());
                resp.setClosingTime(timeConfigDto.getClosingTime());
                List<DeptPersonDto> respPersonList = new ArrayList<>();
                for (GroupPersonWorkShiftResp.TimeConfigPerson timeConfigPerson : timeConfigPersonArrayList) {
                    if (timeConfigDto.getId().equals(timeConfigPerson.getTimeConfigDto().getId())) {
                        DeptPersonDto deptPersonDto = deptPersonService.selectCacheById(timeConfigPerson.getDeptPersonId());
                        if (deptPersonDto != null) {
                            respPersonList.add(deptPersonDto);
                        }
                    }
                    resp.setPersons(respPersonList);
                }
                resultList.add(resp);
            }
        }
        return Response.<List<GroupPersonWorkShiftResp>>ok().wrap(resultList);
    }

    @GetMapping("quertPersonWorkTimeByGroupIdAndMonth")
    @Operation(summary = "查看选中考勤组的排班日历")
    public Response<List<GroupPersonWorkTimeResp>> quertPersonWorkTimeByGroupId(
            @Parameter(description = "考勤组id") @RequestParam(required = true) Long groupId,
            @Parameter(description = "月份 yyyy-MM", required = true) @RequestParam String month) {

        SessionHolder.checkEmp();
        //查询列表数据
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));

        SchedulingAttendanceGroupDto schedulingAttendanceGroupDto = schedulingAttendanceGroupService.selectById(groupId);
        if (schedulingAttendanceGroupDto == null) {
            return Response.error("考勤组不存在，请联系管理员");
        }

        // 手动排班才把日期条件放进去
        if (SchedulingAttendanceGroupConstants.SchedulingTypeEnum.FIX.getType().equals(schedulingAttendanceGroupDto.getShiftSystemType())) {
            request.getParams().remove("month");
        }

        request.put(LambdaUtil.getFieldName(SchedulingAttendanceGroupPersonWorkTimeConfigDto::getSchedulingAttendanceGroupId), groupId);

        // 查询配置
        List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> schedulingAttendanceGroupPersonWorkTimeConfigDtos =
                schedulingAttendanceGroupPersonWorkTimeConfigService.queryListWithoutPadding(request.getParams());

        List<GroupPersonWorkTimeResp> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(schedulingAttendanceGroupPersonWorkTimeConfigDtos)) {
            return Response.<List<GroupPersonWorkTimeResp>>ok().wrap(result);
        }

        // 手动排班日历
        if (schedulingAttendanceGroupDto.getShiftSystemType().equals(SchedulingAttendanceGroupConstants.SchedulingTypeEnum.SCHEDULING.getType())) {
            // 查询出来可能有相同日期的，先按日期去重
            List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> uniqueDtos = removeDuplicateDates(schedulingAttendanceGroupPersonWorkTimeConfigDtos);

            // 日期排序
            List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> sortedList =
                    uniqueDtos.stream().sorted((a, b) -> DateUtil.compare(a.getDate(), b.getDate())).collect(Collectors.toList());

            // 填充数据
            for (SchedulingAttendanceGroupPersonWorkTimeConfigDto configDto : sortedList) {
                GroupPersonWorkTimeResp resp = new GroupPersonWorkTimeResp();
                resp.setDate(DateUtils.format(configDto.getDate(), DateUtils.FormatType.SIMPLE));
                resp.setSituationType(SchedulingAttendanceDailyConstants.SituationTypeEnum.WORK.getType());
                resp.setSituation(SchedulingAttendanceDailyConstants.SituationTypeEnum.WORK.getDesc());
                result.add(resp);
            }
        }

        // 固定班
        if (schedulingAttendanceGroupDto.getShiftSystemType().equals(SchedulingAttendanceGroupConstants.SchedulingTypeEnum.FIX.getType())) {
            SchedulingAttendanceGroupPersonWorkTimeConfigDto personWorkTimeConfigDto = schedulingAttendanceGroupPersonWorkTimeConfigDtos.get(0);
            List<FixWorkTimeBindingDto> fixWorkTimeBindingDtos = JacksonUtils.parseArray(personWorkTimeConfigDto.getTimeConfigArr(), FixWorkTimeBindingDto.class);

            List<Date> monthDates = getMonthDates(DateUtil.parse(month + "-01 00:00:00"));
            for (Date date : monthDates) {
                List<FixWorkTimeBindingDto> fixWorkTimeBindingConfig = fixWorkTimeBindingDtos.parallelStream()
                        .collect(Collectors.groupingBy(FixWorkTimeBindingDto::getDay))
                        .get(DateUtil.dayOfWeekEnum(date).getValue()
                        );
                List<SchedulingTimeConfigDto> timeConfigDtoList = fixWorkTimeBindingConfig.get(0).getTimeConfigDtoList();
                GroupPersonWorkTimeResp resp = new GroupPersonWorkTimeResp();
                resp.setDate(DateUtils.format(date, DateUtils.FormatType.SIMPLE));
                // 没有查询到班 就先填充休息
                if (CollectionUtils.isEmpty(timeConfigDtoList)) {
                    resp.setSituationType(SchedulingAttendanceDailyConstants.SituationTypeEnum.REST.getType());
                    resp.setSituation(SchedulingAttendanceDailyConstants.SituationTypeEnum.REST.getDesc());
                } else {
                    resp.setSituationType(SchedulingAttendanceDailyConstants.SituationTypeEnum.WORK.getType());
                    resp.setSituation(SchedulingAttendanceDailyConstants.SituationTypeEnum.WORK.getDesc());
                }
                result.add(resp);
            }

            // 遍历一次result,查看是否绑定休假日历，休假日历日期填充上去
            if (schedulingAttendanceGroupDto.getSchedulingCalendarId() != null) {
                List<SchedulingCalendarConfigBindingDto> calBindingDtos = calendarConfigBindingService.selectListByConfigId(schedulingAttendanceGroupDto.getSchedulingCalendarId());
                if (CollectionUtils.isNotEmpty(calBindingDtos)) {
                    for (GroupPersonWorkTimeResp groupPersonWorkTimeResp : result) {
                        for (SchedulingCalendarConfigBindingDto calendarConfigBindingDto : calBindingDtos) {
                            if (DateUtil.parse(groupPersonWorkTimeResp.getDate(), DateUtils.FormatType.SIMPLE.getType())
                                    .equals(calendarConfigBindingDto.getDate())) {
                                // 节假日
                                if (calendarConfigBindingDto.getType().equals(SchedulingCalendarConfigConstants.DateType.HOLIDAY.getType())) {
                                    groupPersonWorkTimeResp.setSituationType(SchedulingAttendanceDailyConstants.SituationTypeEnum.VACATION.getType());
                                    groupPersonWorkTimeResp.setSituation(SchedulingAttendanceDailyConstants.SituationTypeEnum.VACATION.getDesc());
                                }

                                // 休息日
                                if (calendarConfigBindingDto.getType().equals(SchedulingCalendarConfigConstants.DateType.REST.getType())) {
                                    groupPersonWorkTimeResp.setSituationType(SchedulingAttendanceDailyConstants.SituationTypeEnum.REST.getType());
                                    groupPersonWorkTimeResp.setSituation(SchedulingAttendanceDailyConstants.SituationTypeEnum.REST.getDesc());
                                }
                                break;
                            }
                        }
                    }
                }
            }
        }

        return Response.<List<GroupPersonWorkTimeResp>>ok().wrap(result);
    }

    /**
     * 根据date去重
     *
     * @param dtos
     * @return
     */
    public static List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> removeDuplicateDates(List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> dtos) {
        Set<Date> uniqueDates = new HashSet<>();
        List<SchedulingAttendanceGroupPersonWorkTimeConfigDto> uniqueDtos = new ArrayList<>();

        for (SchedulingAttendanceGroupPersonWorkTimeConfigDto dto : dtos) {
            Date date = dto.getDate();
            if (!uniqueDates.contains(date)) {
                uniqueDates.add(date);
                uniqueDtos.add(dto);
            }
        }
        return uniqueDtos;
    }

    /**
     * 传入日期获取开头到结尾
     *
     * @param date
     * @return
     */
    public static List<Date> getMonthDates(Date date) {
        List<Date> dates = new ArrayList<>();
        Date monthStart = DateUtil.beginOfMonth(date);
        Date monthEnd = DateUtil.endOfMonth(date);

        Date currentDay = monthStart;
        while (!currentDay.after(monthEnd)) {
            dates.add(currentDay);
            currentDay = DateUtil.offsetDay(currentDay, 1);
        }

        return dates;
    }

}
